/*
 * @(#)Node.java $version 2012-3-2
 * 
 * Copyright 2011 RogueDevelopment Gruop. All rights Reserved.
 * ROGUEDEVELOPMENT PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
package com.nadostar.extensions.util;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author LEESUNG
 * 
 */
public class Node<V, N extends Node<V, N>> {
	protected final String name;

	protected V value;
	protected N parent;

	protected Map<String, N> children = new LinkedHashMap<String, N>();

	/**
	 * Instantiates a new node.
	 * 
	 * @param name the name
	 */
	public Node(String name) {
		this.name = name;
	}

	/**
	 * Instantiates a new node.
	 * 
	 * @param name the name
	 * @param value the value
	 */
	public Node(String name, V value) {
		this.name = name;
		this.value = value;
	}

	/**
	 * Checks if is root.
	 * 
	 * @return true, if is root
	 */
	public boolean isRoot() {
		return parent == null;
	}

	/**
	 * Name.
	 * 
	 * @return the string
	 */
	public String name() {
		return name;
	}

	/**
	 * Value.
	 * 
	 * @return the v
	 */
	public V value() {
		return value;
	}

	/**
	 * Self.
	 * 
	 * @return the n
	 */
	@SuppressWarnings("unchecked")
	public N self() {
		return (N)this;
	}

	/**
	 * Parent.
	 * 
	 * @return the n
	 */
	public N parent() {
		return parent;
	}

	/**
	 * Value.
	 * 
	 * @param value the value
	 * 
	 * @return the n
	 */
	public N value(V value) {
		this.value = value;
		return self();
	}

	/**
	 * Find.
	 * 
	 * @param name the name
	 * 
	 * @return the n
	 */
	public N find(String name) {
		return children.get(name);
	}

	/**
	 * Find recursive.
	 * 
	 * @param name the name
	 * 
	 * @return the n
	 */
	public N findRecursive(String name) {
		int index = name.indexOf('/');
		
		if (index < 0) {
			return find(name);
		}
		
		N child = find(name.substring(0, index));
		
		if (child == null) {
			return null;
		}
		
		return child.findRecursive(name.substring(index + 1));
	}

	/**
	 * Creates the recursive.
	 * 
	 * @param name the name
	 * @param value the value
	 * 
	 * @return the n
	 */
	public N createRecursive(String name, V value) {
		name = name.endsWith("/") ? name.substring(0, name.length() - 1) : name;
		int index = name.indexOf('/');
		
		if (index < 0) {
			N prev = find(name);
			return prev == null ? newChild(name, value) : prev.value(value);
		}
		
		String childName = name.substring(0, index);
		N child = find(childName);
		
		if (child == null) {
			child = newChild(childName);
		}

		return child.createRecursive(name.substring(index + 1), value);
	}

	/**
	 * New child.
	 * 
	 * @param name the name
	 * 
	 * @return the n
	 */
	public N newChild(String name) {
		return newChild(name, null);
	}

	/**
	 * New child.
	 * 
	 * @param name the name
	 * @param value the value
	 * 
	 * @return the n
	 */
	public N newChild(String name, V value) {
		N newNode = create(name, value);
		newNode.parent = self();
		children.put(name, newNode);
		return newNode;
	}

	/**
	 * Creates the.
	 * 
	 * @param name the name
	 * 
	 * @return the n
	 */
	protected N create(String name) {
		return create(name, null);
	}

	/**
	 * Creates the.
	 * 
	 * @param name the name
	 * @param value the value
	 * 
	 * @return the n
	 */
	@SuppressWarnings("unchecked")
	protected N create(String name, V value) {
		return (N)new Node(name, value);
	}
}

